package  
{
	import flash.display.MovieClip;
	import flash.events.Event;
	import logics.CustomEvent;
	
	public class Tween extends MovieClip  
	{
		private var _obj:Object;
		private var _prop:Object;
		private var _calc:Function;
		private var _evt:String;
		
		public static const cubicIn:int = 0;
		public static const cubicOut:int = 1;
		public static const cubicInOut:int = 2;
		public static const linearIn:int = 4;
		public static const circleIn:int = 5;
		public static const circleInOut:int = 6;
		public static const sineIn:int = 7;
		public static const sineOut:int = 8;
		public static const sineInOut:int = 9;
		
		
		public function getValues(start:Number, end:Number, steps:Number):Array
		{
			var v:Array = new Array();
			for (var i:int = 0; i < steps + 1; i++)
			{
				v.push(_calc(i, start, end, steps));
			}
			return v;
		}
		
		public function easeLinear(i:int, start:Number, end:Number, steps:Number):Number
		{
			var c:Number = end - start;
			var step:Number = c / steps;
			
			return start + (step * i);
		}
		
		public function easeInCubic(i:int, start:Number, end:Number, steps:Number):Number
		{
			var c:Number = end - start;
			var step:Number = Math.pow(i / steps, 3);
			
			return start + ( c * step );
		}
		
		public function easeOutCubic(i:int, start:Number, end:Number, steps:Number):Number
		{
			var c:Number = end - start;
			var step:Number = Math.pow((i / steps) - 1, 3) + 1;
			
			return start + ( c * step );
		}
		
		public function easeInOutCubic(i:int, start:Number, end:Number, steps:Number):Number
		{
			var c:Number = (end - start)/2;
			var t:Number = i / (steps / 2);
			
			if (t < 1)
			{
				return start + (c * Math.pow(t, 3));
			}
			
			return start + (c * ( Math.pow(t - 2, 3) + 2 ));
		}
		

		public function easeInOutCircle(i:int, start:Number, end:Number, steps:Number):Number
		{
			var c:Number = (end - start) / 2;
			var t:Number = i / (steps / 2);
			var step:Number;
			
			if (t < 1)
			{
				step = 1 - Math.sqrt(1 - (t * t));
				return start + (c * step);
			}
			t -= 2;
			step = Math.sqrt(1 - (t * t)) + 1;
			return start + (c * step);
		}
		
		public function easeInCircle(i:int, start:Number, end:Number, steps:Number):Number
		{
			var c:Number = end - start;
			var t:Number = i / steps;
			var step:Number = 1 - Math.sqrt(1 - (t * t));
			
			return start + (c * step);
		}
		
		public function easeInOutSine(i:int, start:Number, end:Number, steps:Number):Number
		{
			var c:Number = (end - start) / 2;
			var step:Number = (1 - Math.cos(Math.PI * (i / steps)));
			
			return start + (c * step);			
		}
		
		public function easeOutSine(i:int, start:Number, end:Number, steps:Number):Number
		{
			var c:Number = end - start;
			var step:Number = Math.sin(i / steps * (Math.PI / 2));
			
			return start + (c * step);
		}
		
		public function easeInSine(i:int, start:Number, end:Number, steps:Number):Number
		{
			var c:Number = end - start;
			var step:Number = 1 - Math.cos(i / steps * (Math.PI / 2));
			
			return start + (c * step);
		}
		
		public function update(e:Event):void
		{
			var property:Object; 
			var finished:Boolean = true;
			
			for (var i:* in _prop)
			{
				property = _prop[i];
			
				if (!property.finished)
				{
					if (property.index == property.steps + 1)
					{
						property.finished = true;
						if (_evt != null)
						{
							_obj.dispatchEvent( new CustomEvent(_evt) );
							trace(property + " " + property.values[property.steps]);
						}
					}
					else
					{
						_obj[i] = property.values[property.index];
						property.index++;
						finished = false;
					}
				}
			}
			
			isFinished(finished);
		}
		
		public function isFinished(finished:Boolean):void
		{
			if (finished)
			{
				removeEventListener(Event.ENTER_FRAME, update);
			}
		}
		
		public function start():void
		{
			var property:Object; 
			
			for (var i:* in _prop)
			{
				property = _prop[i];
				property.values = getValues(property.start, property.end, property.steps);
				property.index = 0;
				property.finished = false;
			}	
			addEventListener(Event.ENTER_FRAME, update);
		}
		
		public function Tween(o:Object, p:Object, t:int = 0, evt:String=null) 
		{
			_obj = o;
			_prop = p;
			_evt = evt;
			
			switch(t)
			{
				case 9:
				_calc = easeInOutSine;
				break;
				
				case 6:
				_calc = easeInOutCircle;
				break;
				
				case 0:
				_calc = easeInCubic;
				break;
				
				case 1:
				_calc = easeOutCubic;
				break;
				
				case 2:
				_calc = easeInOutCubic;
				break;
				
				case 7:
				_calc = easeInSine;
				break;
				
				case 8:
				_calc = easeOutSine;
				break;
			
				case 5:
				_calc = easeInCircle;
				break;
			
				case 6:
				_calc = easeInOutCircle;
				break;
				
				case 4:
				_calc = easeLinear;
				break;
			}
		}
	}
}